package com.tools.utils;


import org.openjdk.jmh.annotations.*;

import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

/**
 * 基准测试：
 * 对比 for 循环 / stream / parallelStream 在 100 万数据下的耗时
 */
@BenchmarkMode(Mode.AverageTime)       // 平均耗时
@OutputTimeUnit(TimeUnit.MILLISECONDS) // 毫秒
@State(Scope.Thread)
public class LoopVsStreamBenchmark {

    private static final int SIZE = 1_000_000;

    private List<Integer> data;

    @Setup(Level.Iteration)
    public void setup() {
        // 初始化 100 万个整数
        data = IntStream.range(0, 1_000_000).boxed().collect(Collectors.toList());
    }

    @Benchmark
    public long testForLoop() {
        long sum = 0;
        for (int i = 0; i < data.size(); i++) {
            int val = data.get(i);
            if (val % 2 == 0) {
                sum += val;
            }
        }
        return sum;
    }

    @Benchmark
    public long testStream() {
        return data.stream()
                .filter(x -> x % 2 == 0)
                .mapToLong(x -> x)
                .sum();
    }

    @Benchmark
    public long testParallelStream() {
        return data.parallelStream()
                .filter(x -> x % 2 == 0)
                .mapToLong(x -> x)
                .sum();
    }


    public static void main(String[] args) {
        // 初始化数据
        List<Integer> data = IntStream.range(0, SIZE).boxed().collect(Collectors.toList());

        // 预热（避免 JIT 编译影响）
        for (int i = 0; i < 5; i++) {
            testForLoop(data);
            testStream(data);
            testParallelStream(data);
        }

        // 正式测试
        long start, end;

        // For 循环
        start = System.currentTimeMillis();
        long sumFor = testForLoop(data);
        end = System.currentTimeMillis();
        System.out.println("for loop sum=" + sumFor + " 耗时: " + (end - start) + " ms");

        // Stream
        start = System.currentTimeMillis();
        long sumStream = testStream(data);
        end = System.currentTimeMillis();
        System.out.println("stream sum=" + sumStream + " 耗时: " + (end - start) + " ms");

        // Parallel Stream
        start = System.currentTimeMillis();
        long sumParallel = testParallelStream(data);
        end = System.currentTimeMillis();
        System.out.println("parallelStream sum=" + sumParallel + " 耗时: " + (end - start) + " ms");
    }

    private static long testForLoop(List<Integer> data) {
        long sum = 0;
        for (int val : data) {
            if (val % 2 == 0) {
                sum += val;
            }
        }
        return sum;
    }

    private static long testStream(List<Integer> data) {
        return data.stream()
                .filter(x -> x % 2 == 0)
                .mapToLong(x -> x)
                .sum();
    }

    private static long testParallelStream(List<Integer> data) {
        return data.parallelStream()
                .filter(x -> x % 2 == 0)
                .mapToLong(x -> x)
                .sum();
    }


}
